#include "stdafx.h"
#include <assert.h>
#include<stdlib.h>
#include <time.h>

#include <math.h>
#include "VIBE.hxx"

#define N 25
#define R 15
#define ZMIN	3
#define PHI		16

VIBE::VIBE()
{
	_frameWidth = 0;
	_frameHeight = 0;
	_frameWidthStrip = 0;

	_sphereRadius = R;
	_pixelSamples = N;
	
	_backgroundThreshold = ZMIN;
	_subSampling = PHI;

	_image = 0;
	_segMap = 0;
	
	_samples = 0;

	_borderWidth = 0;
}

VIBE::~VIBE()
{
	if( _samples )
	{
		for( int i = 0; i < _pixelSamples; i ++ )
			if( _samples[ i ] )
			{
				delete [] _samples[ i ];
				_samples[ i ] = 0;
			}
		delete [] _samples;
		_samples = 0;
	}
}

void VIBE::initialize()
{
	assert( (_frameWidth < 1 || _frameHeight < 1 || _frameWidthStrip < 1) || "Please set frame info for initialize...\n");

	srand((int)time(0));

	_samples = new unsigned char*[ _pixelSamples ];

	for( int i = 0; i < _pixelSamples; i ++ )
		_samples[ i ] = new unsigned char[ _frameHeight * _frameWidthStrip ];


	int tq = sqrtf( _pixelSamples );
	_borderWidth = tq / 2;

	for( int y = _borderWidth; y < _frameHeight - _borderWidth; y ++ )
	{
		for( int x = _borderWidth; x < _frameWidth - _borderWidth; x ++ )
		{
			int c = 0; 
			for( int i = -_borderWidth; i <= _borderWidth && c < _pixelSamples ; i ++ )
			{
				for( int j = -_borderWidth; j <= _borderWidth && c < _pixelSamples; j ++ )
					if( c < _pixelSamples - _backgroundThreshold )
						*(_samples[ c++ ] + y * _frameWidthStrip + x) = *(_image + ( y + i ) * _frameWidthStrip + ( x + j ));
					else
						*(_samples[ c++ ] + y * _frameWidthStrip + x) = *(_image +  y * _frameWidthStrip + x);

			}
		}
	}
}

void VIBE::update()
{
	for( int x = 0; x < _frameWidth; x ++ )
	{
		for( int y = 0; y < _frameHeight; y ++ )
		{
			int count = 0, index = 0, dist = 0;

			if( y < _borderWidth || x < _borderWidth || x >= _frameWidth - _borderWidth || y >= _frameHeight - _borderWidth )
			{
				*(_segMap + y * _frameWidthStrip + x ) = 0;
				continue;
			}

			while( count < _backgroundThreshold && index < _pixelSamples )
			{
				dist = abs( *(_image + y * _frameWidthStrip + x) -
					*(_samples[ index ] + y * _frameWidthStrip + x ) );

				if( dist < _sphereRadius )
					count ++;

				index ++;
			}


			if( count >= _backgroundThreshold )
			{
				*(_segMap + y * _frameWidthStrip + x ) = 0;

				int rand = getRandomSubSample();
                //if( rand == 0 )
              if( rand < 6)
				{
					rand = getRandomSample();
					*(_samples[ rand ] + y * _frameWidthStrip + x ) = *( _image + y * _frameWidthStrip + x );
				}

				rand = getRandomSubSample();
                //if( rand == 0 )
               if( rand < 6 )
				{
					int xg, yg;

					xg = getRandomNeightXCoordinate(x);
					yg = getRandomNeightYCoordinate(y);

					rand = getRandomSample();
					*(_samples[ rand ] + yg * _frameWidthStrip + xg ) = *( _image + y * _frameWidthStrip + x );
				}
				
			}
			else
			{
				*(_segMap  + y * _frameWidthStrip + x ) = 255;
			}
		}
	}
}

int VIBE::getRandomSample()
{
	int val = _pixelSamples * 1.0 * rand() / RAND_MAX;
	
	if( val == _pixelSamples )
		return val - 1;
	else
		return val;
		
}

int VIBE::getRandomSubSample()
{
	int val = _subSampling * 1.0 * rand() / RAND_MAX;
	if( val == _subSampling )
		return val - 1;
	else
		return val;
	
}

int VIBE::getRandomNeightXCoordinate( int x )
{
    int val = 4 * 1.0 * rand() / RAND_MAX - 2;
	if( x + val >= _frameWidth || x + val < 0 )
		return x;
	else
		return x + val;
}

int VIBE::getRandomNeightYCoordinate( int y )
{
    int val = 4 * 1.0 * rand() / RAND_MAX - 2;
	if( y + val >= _frameWidth || y + val < 0 )
		return y;
	else
		return y + val;
}
